package com.example.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/*
* 在不同切面类中，默认按照切面类的名字字母排序，执行先后顺序
* 在不改变类名的情况下可以使用@Order注解来控制执行的先后顺序，数字越小越先执行
* */
//@Order(1)
@Slf4j
@Aspect
@Component
public class Timeaspect {
    /*
    * 将aop切片的公共切点以表达式的形式抽取出来，需要用到时以表达式的形式使用即可
    * 本类中使用可直接在表达式中方法名()即可
    * 在其他切面中使用该切点则需要全类名即com.example.aspect.Timeaspect.put()
    *   execution(* com.example.controller..*.*(..))
    *   * 表示访问修饰符（public，*）
    *   com.example.controller..* 表示作用于该路径下的所有类名
    *   .*(..) 方法名（方法参数）.*所有方法..多个连续的任意符号，可以通配任意层级的方法名，参数
    *   (*)方法名必须有一个参数
    *   *单个任意字符
    *   *service匹配以service结尾的任意方法字符
    *   service*匹配以service开头的任意方法字符
    * */
    @Pointcut("execution(* com.example.controller.upload.*(..))")
    public void put() {};

    /*

    // 使用AOP切面记录每次接口调用产生的时长
    @Around("put()")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable{
        // 在原始操作的上方添加
        long begin = System.currentTimeMillis();
        Object result = joinPoint.proceed();// 调用原始操作
        // 原始操作结束后的代码
        long end = System.currentTimeMillis();
        log.info("总计用时:{}",(end - begin));
        return result;
    }*/
    /*
    * 前置通知，此注解的通知方式是在目标方法执行前执行
    * */
    @Before("com.example.aspect.Timeaspect.put()")
    public void BeforeTime() {
        log.info("Timeaspect BeforeTime...");
    }


    /*
    * 环绕通知，此注解的通知方式是在目标方法执行前，后都执行
    * 需要调用ProceedingJoinPoint.proceed()方法让原始方法执行，其他通知则不需要
    * 此方式需要返回值，否则目标方法拿不到值
    *
    * */

    @Around("@annotation(com.example.aspect.MyLog)")
    // @annotation(com.example.aspect.MyLog)这个标识符表示只有加上这个注解的类才会被aop控制
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        // 在原始操作的上方添加
        long begin = System.currentTimeMillis();
        Object result = joinPoint.proceed();// 调用原始操作
        // 原始操作结束后的代码
        long end = System.currentTimeMillis();
        // 使用AOP切面记录每次接口调用产生的时长
        log.info("总计用时:{}", (end - begin));
        return result;
    }
    /*
    * 后置通知，此注解的通知方式是在目标方法执行后执行
    * */
    @After("com.example.aspect.Timeaspect.put()")
    public void AfterTime() {
        log.info("Timeaspect AfterTime...");
    }
    /*
    * 返回后通知，此注解的通知方式是在目标方法执行后执行，且方法若是有异常则不执行
    * */
    @AfterReturning("com.example.aspect.Timeaspect.put()")
    public void AfterReturningTime() {
        log.info("Timeaspect AfterReturningTime...");
    }
    /*
    * 异常后通知，此注解的通知方式是在目标方法执行发生异常才会执行
    * */
    @AfterThrowing("put()")
    public void AfterThrowingTime() {
        log.info("Timeaspect AfterThrowingTime...");
    }
}
